home *** CD-ROM | disk | FTP | other *** search
/ Pascal Super Library / Pascal Super Library (CW International)(1997).bin / EDIT_UTL / TRIVED09 / GENERICF.PAS next >
Pascal/Delphi Source File  |  1995-04-22  |  30KB  |  1,595 lines

  1. unit genericf;  {generic functions unit - not rnr-specific at all}
  2.  
  3. {
  4.  
  5. Russell Schulz - russell@alpha3.ersys.edmonton.ab.ca (950216)
  6.  
  7. Copyright 1995 Russell Schulz
  8.  
  9. this code is not in the Public Domain
  10.  
  11. permission is granted to use these routines in any application regardless
  12. of commercial status as long as the author of these routines assumes no
  13. liability for any damages whatsoever for any reason.  have fun.
  14.  
  15. }
  16.  
  17. {
  18. version of this unit: 1ish
  19. }
  20.  
  21. {$define floatingpoint}
  22. {$undef floatingpoint}
  23.  
  24. interface
  25.  
  26. uses dos;
  27.  
  28. const
  29.   tab=#9;
  30.  
  31. function max(a,b: integer): integer;
  32. function min(a,b: integer): integer;
  33. function wordtozstring(w: word; width: integer): string;
  34. function integertozstring(i: integer; width: integer): string;
  35. function longtozstring(l: longint; width: integer): string;
  36. function time: string;
  37. function timedigits: string;
  38. function dow: integer;
  39. function cdow: string;
  40. function dayofmonth: integer;
  41. function month: integer;
  42. function extmonthname(themonth: integer): string;
  43. function monthname: string;
  44. function year: integer;
  45. function getenv(s: string): string;
  46. function numoccur(c: char; s: string): integer;
  47. function hasany(c: char; s: string): boolean;
  48. function hasno(c: char; s: string): boolean;
  49. function unquote(s: string): string;
  50. function crepl(s: string; cold, cnew: char): string;
  51. function unslash(s: string): string;
  52. function unbackslash(s: string): string;
  53. function ununderscore(s: string): string;
  54. function uncomma(s: string): string;
  55. function srepl(s: string; sold, snew: string): string;
  56. function unspace(s: string): string;
  57. function atow(s: string): word;
  58. function atoi(s: string): integer;
  59. function atol(s: string): longint;
  60. function wtoa(w: word): string;
  61. function itoa(i: integer): string;
  62. function ltoa(l: longint): string;
  63. function lowcase(c: char): char;
  64. function upper(s: string): string;
  65. function lower(s: string): string;
  66. function proper(s: string): string;
  67. function ltrim(s: string): string;
  68. function trim(s: string): string;
  69. function right(s: string; i: integer): string;
  70. function getfirstw(s: string): string;
  71. function chopfirstw(var s: string): string;
  72. function getquoted(s: string): string;
  73. function randomletter: char;
  74. function randomdigit: char;
  75. function getfromaddr(from: string): string;
  76. function getfromname(from: string): string;
  77. function chop(s: string; i: integer): string;
  78. function nore(s: string): string;
  79. function monthstringtointeger(monthstr: string): integer;
  80. function isalpha(c: char): boolean;
  81. function isdigit(c: char): boolean;
  82. function islower(c: char): boolean;
  83. function snatchint(var s: string): integer;
  84. function isdev(s: string): boolean;
  85. function illegalfn(fn: string): boolean;
  86. function suspiciousfn(fn: string): boolean;
  87. function highestartin(groupdir: string): word;
  88. function getuniqfile(groupdir: string): string;
  89. function getuniqfext(basename: string): string;
  90. function expand(str: string): string;
  91. function rot13(s: string): string;
  92. function indir(filespec,dir: string): boolean;
  93. function default(defaultstr,possiblyemptystr: string): string;
  94. function rpos(sub: string; whole: string): integer;
  95. function rposc(s: string; c: char): integer;
  96. function fexists(fn: string): boolean;
  97. function dexists(dn: string): boolean;
  98. function ftimestamp(fn: string): longint;
  99. function withbackslash(s: string): string;
  100. function nobeep(s: string): string;
  101. function nonastychar(s: string): string;
  102. function gettag(tag: string; s: string): string;
  103. function hexchar(i: integer): char;
  104. function partialmatch(cmd, template, minimum: string): boolean;
  105. function doserrorno: byte;
  106. function wordwith(c:char; s: string): string;
  107. function isasciifile(fn: string): boolean;
  108.  
  109. {$ifdef VER40}
  110. function dosversion: word;
  111. {$endif}
  112.  
  113. {$ifdef floatingpoint}
  114. function ator(s: string): real;
  115. function rtoa(r: real): string;
  116. function rwptoa(r: real; width: integer; precision: integer): string;
  117. {$endif}
  118.  
  119. implementation
  120.  
  121. function max;
  122.  
  123. begin
  124.   if a>b then max := a else max := b;
  125. end;
  126.  
  127. function min;
  128.  
  129. begin
  130.   min := -max(-a,-b);
  131. end;
  132.  
  133. function wordtozstring;
  134.  
  135. var
  136.   result: string;
  137.  
  138. begin
  139.   str(w,result);
  140.  
  141.   while length(result)<width do
  142.     result := '0'+result;
  143.  
  144.   wordtozstring := result;
  145. end;
  146.  
  147. function integertozstring;
  148.  
  149. var
  150.   result: string;
  151.  
  152. begin
  153.   str(i,result);
  154.  
  155.   while length(result)<width do
  156.     result := '0'+result;
  157.  
  158.   integertozstring := result;
  159. end;
  160.  
  161. function longtozstring;
  162.  
  163. var
  164.   result: string;
  165.  
  166. begin
  167.   str(l,result);
  168.  
  169.   while length(result)<width do
  170.     result := '0'+result;
  171.  
  172.   longtozstring := result;
  173. end;
  174.  
  175. function time;
  176.  
  177. var
  178.   h,m,s,s00: word;
  179.  
  180. begin
  181.   gettime(h,m,s,s00);
  182.   time :=
  183.    integertozstring(h,2)+':'+integertozstring(m,2)+':'+integertozstring(s,2);
  184. end;
  185.  
  186. function timedigits;
  187.  
  188. var
  189.   h,m,s,s00: word;
  190.  
  191. begin
  192.   gettime(h,m,s,s00);
  193.   timedigits :=
  194.    integertozstring(h,2)+integertozstring(m,2)+integertozstring(s,2);
  195. end;
  196.  
  197. function dow;
  198.  
  199. var
  200.   y,m,d,realdow: word;
  201.  
  202. begin
  203.   getdate(y,m,d,realdow);
  204.   dow := realdow;
  205. end;
  206.  
  207. function cdow;
  208.  
  209. var
  210.   result: string;
  211.   thedow: integer;
  212.  
  213. begin
  214.   thedow := dow;
  215.  
  216.   result := 'Sunday';
  217.   if thedow=1 then result := 'Monday';
  218.   if thedow=2 then result := 'Tuesday';
  219.   if thedow=3 then result := 'Wednesday';
  220.   if thedow=4 then result := 'Thursday';
  221.   if thedow=5 then result := 'Friday';
  222.   if thedow=6 then result := 'Saturday';
  223.  
  224.   cdow := result;
  225. end;
  226.  
  227. function dayofmonth;
  228.  
  229. var
  230.   y,m,d,dow: word;
  231.  
  232. begin
  233.   getdate(y,m,d,dow);
  234.   dayofmonth := d;
  235. end;
  236.  
  237. function month;
  238.  
  239. var
  240.   y,m,d,dow: word;
  241.  
  242. begin
  243.   getdate(y,m,d,dow);
  244.   month := m;
  245. end;
  246.  
  247. function extmonthname;
  248.  
  249. var
  250.   result: string;
  251.  
  252. begin
  253.   result := 'January';
  254.   if themonth=2  then result := 'February';
  255.   if themonth=3  then result := 'March';
  256.   if themonth=4  then result := 'April';
  257.   if themonth=5  then result := 'May';
  258.   if themonth=6  then result := 'June';
  259.   if themonth=7  then result := 'July';
  260.   if themonth=8  then result := 'August';
  261.   if themonth=9  then result := 'September';
  262.   if themonth=10 then result := 'October';
  263.   if themonth=11 then result := 'November';
  264.   if themonth=12 then result := 'December';
  265.  
  266.   extmonthname := result;
  267. end;
  268.  
  269. function monthname;
  270.  
  271. begin
  272.   monthname := extmonthname(month);
  273. end;
  274.  
  275. function year;
  276.  
  277. var
  278.   y,m,d,dow: word;
  279.  
  280. begin
  281.   getdate(y,m,d,dow);
  282.   year := y;
  283. end;
  284.  
  285. function getenv;
  286.  
  287. var
  288.   result: string;
  289.  
  290.   i: integer;
  291.   envseg: word;
  292.   envread: integer;
  293.   firstb: byte;
  294.   thisb: byte;
  295.   varname: string;
  296.   vardata: string;
  297.   done: boolean;
  298.  
  299. begin
  300.   result := '';
  301.  
  302.   envseg := memw[prefixseg:$2c];
  303.  
  304.   envread := 0;
  305.   repeat
  306.     firstb := mem[envseg:envread];
  307.  
  308.     if firstb>0 then
  309.       begin
  310.         varname := '';
  311.  
  312.         repeat
  313.           thisb := mem[envseg:envread];
  314.           inc(envread);
  315.           if thisb<>ord('=') then
  316.             varname := varname+chr(thisb);
  317.         until thisb=ord('=');
  318.  
  319.         vardata := '';
  320.  
  321.         repeat
  322.           thisb := mem[envseg:envread];
  323.           inc(envread);
  324.           if thisb>0 then
  325.             vardata := vardata+chr(thisb);
  326.         until thisb=0;
  327.  
  328.         done := (varname=s);
  329.         if done then
  330.           result := vardata;
  331.     end;
  332.   until (firstb=0) or done;
  333.  
  334.   getenv := result;
  335. end;
  336.  
  337. function numoccur;
  338.  
  339. var
  340.   result: integer;
  341.   i: integer;
  342.  
  343. begin
  344.   result := 0;
  345.  
  346.   for i := 1 to length(s) do
  347.     if s[i]=c then
  348.       inc(result);
  349.  
  350.   numoccur := result;
  351. end;
  352.  
  353. function hasany;
  354.  
  355. begin
  356.   hasany := (numoccur(c,s)<>0);
  357. end;
  358.  
  359. function hasno;
  360.  
  361. begin
  362.   hasno := not hasany(c,s);
  363. end;
  364.  
  365. function unquote;
  366.  
  367. begin
  368.   if (s[1]='"') and (s[length(s)]='"') then
  369.     unquote := copy(s,2,length(s)-2)
  370.   else
  371.     unquote := s;
  372. end;
  373.  
  374. function crepl;
  375.  
  376. var
  377.   result: string;
  378.   i: integer;
  379.  
  380. begin
  381.   result := s;
  382.  
  383.   for i := 1 to length(result) do
  384.     if result[i]=cold then
  385.       result[i] := cnew;
  386.  
  387.   crepl := result;
  388. end;
  389.  
  390. function unslash;
  391.  
  392. begin
  393.   unslash := crepl(s,'/','\');
  394. end;
  395.  
  396. function unbackslash;
  397.  
  398. begin
  399.   if s='' then
  400.     unbackslash := s
  401.   else if copy(s,length(s),1)='\' then
  402.     unbackslash := copy(s,1,length(s)-1)
  403.   else
  404.     unbackslash := s;
  405. end;
  406.  
  407. function ununderscore;
  408.  
  409. begin
  410.   ununderscore := crepl(s , '_' , ' ');
  411. end;
  412.  
  413. function uncomma;
  414.  
  415. begin
  416.   uncomma := crepl(s , ',' , ' ');
  417. end;
  418.  
  419. {}{}{}{} { srepl('aa','a','') doesn't work :-( }
  420.  
  421. function srepl;
  422.  
  423. var
  424.   result: string;
  425.   at: integer;
  426.  
  427. begin
  428.   result := s;
  429.   if (sold<>'') and (sold<>snew) then
  430.     begin
  431.       at := 0;
  432.       while at<=length(result)-length(sold) do
  433.         begin
  434.           inc(at);
  435.           if result[at]=sold[1] then
  436.             if copy(result,at,length(sold))=sold then
  437.               begin
  438.                 if sold=result then
  439.                   result := snew
  440.                 else if at=1 then
  441.                   result := snew+copy(result,length(sold)+1,255)
  442.                 else if at=length(result)-length(sold)+1 then
  443.                   result := copy(result,1,at-1)+snew
  444.                 else
  445.                   result :=
  446.                    copy(result,1,at-1)+snew+copy(result,at+length(sold),255);
  447.             end;
  448.         end;
  449.     end;
  450.   srepl := result;
  451. end;
  452.  
  453. function unspace;
  454.  
  455. var
  456.   result: string;
  457.   i: integer;
  458.  
  459. begin
  460.   if (numoccur(' ',s)=0) and (numoccur(tab,s)=0) then
  461.     result := s
  462.   else
  463.     begin
  464.       result := '';
  465.       for i := 1 to length(s) do
  466.         if (s[i]<>' ') and (s[i]<>tab) then
  467.           result := result+s[i];
  468.     end;
  469.  
  470.   unspace := result;
  471. end;
  472.  
  473. function atow;
  474.  
  475. var
  476.   result: word;
  477.   code: word;
  478.  
  479. begin
  480.   val(s,result,code);
  481.   atow := result;
  482. end;
  483.  
  484. function atoi;
  485.  
  486. var
  487.   result: integer;
  488.   code: word;
  489.  
  490. begin
  491.   val(s,result,code);
  492.   atoi := result;
  493. end;
  494.  
  495. function atol;
  496.  
  497. var
  498.   result: longint;
  499.   code: word;
  500.  
  501. begin
  502.   val(s,result,code);
  503.   atol := result;
  504. end;
  505.  
  506. function wtoa;
  507.  
  508. begin
  509.   wtoa := wordtozstring(w,0);
  510. end;
  511.  
  512. function itoa;
  513.  
  514. begin
  515.   itoa := integertozstring(i,0);
  516. end;
  517.  
  518. function ltoa;
  519.  
  520. begin
  521.   ltoa := longtozstring(l,0);
  522. end;
  523.  
  524. function lowcase; {similar to the supplied upcase}
  525.  
  526. begin
  527.   if (c>='A') and (c<='Z') then
  528.     lowcase := chr(ord(c)-ord('A')+ord('a'))
  529.   else
  530.     lowcase := c;
  531. end;
  532.  
  533. function upper;
  534.  
  535. var
  536.   result: string;
  537.   i: integer;
  538.  
  539. begin
  540.   result := s;
  541.  
  542.   for i := 1 to length(s) do
  543.     result[i] := upcase(result[i]);
  544.  
  545.   upper := result;
  546. end;
  547.  
  548. function lower;
  549.  
  550. var
  551.   result: string;
  552.   i: integer;
  553.  
  554. begin
  555.   result := s;
  556.  
  557.   for i := 1 to length(s) do
  558.     result[i] := lowcase(result[i]);
  559.  
  560.   lower := result;
  561. end;
  562.  
  563. function proper;
  564.  
  565. var
  566.   result: string;
  567.   i: integer;
  568.  
  569. begin
  570.   result := s;
  571.  
  572.   if length(s)>0 then
  573.     if (result[1]>='a') and (result[1]<='z') then
  574.       result[1] := upcase(result[1]);
  575.  
  576.   for i := 2 to length(s) do
  577.     if (upcase(result[i])>='A') and (upcase(result[i])<='Z') then
  578.       if result[i-1]=' ' then
  579.         result[i] := upcase(result[i])
  580.       else
  581.         result[i] := lowcase(result[i]);
  582.  
  583.   proper := result;
  584. end;
  585.  
  586. function ltrim;
  587.  
  588. var
  589.   result: string;
  590.  
  591. begin
  592.   result := s;
  593.  
  594.   while ((result[1]=' ') or (result[1]=tab)) and (length(result)>0) do
  595.     result := copy(result,2,255);
  596.  
  597.   ltrim := result;
  598. end;
  599.  
  600. function trim;
  601.  
  602. var
  603.   result: string;
  604.  
  605. begin
  606.   result := s;
  607.  
  608.   while ((result[length(result)]=' ') or (result[length(result)]=tab)) and
  609.    (length(result)>0) do
  610.     result := copy(result,1,length(result)-1);
  611.  
  612.   trim := result;
  613. end;
  614.  
  615. function right;
  616.  
  617. begin
  618.   right := copy(s,max(1,length(s)-i+1),i);
  619. end;
  620.  
  621. function getfirstw;
  622.  
  623. var
  624.   result: string;
  625.   spaceat: integer;
  626.   tabat: integer;
  627.  
  628. begin
  629.   result := trim(ltrim(s));
  630.   spaceat := pos(' ',result);
  631.   tabat := pos(tab,result);
  632.  
  633.   if tabat>0 then
  634.     if (spaceat>0) and (tabat>spaceat) then
  635.       result := copy(result,1,spaceat-1)
  636.     else
  637.       result := copy(result,1,tabat-1)
  638.   else
  639.     if spaceat>0 then
  640.       result := copy(result,1,spaceat-1);
  641.  
  642.   getfirstw := result;
  643. end;
  644.  
  645. function chopfirstw;
  646.  
  647. var
  648.   result: string;
  649.  
  650. begin
  651.   s := trim(ltrim(s));
  652.   result := getfirstw(s);
  653.   s := trim(ltrim(copy(s,length(result)+1,255)));
  654.  
  655.   chopfirstw := result;
  656. end;
  657.  
  658. function getquoted;
  659.  
  660. var
  661.   result: string;
  662.  
  663. begin
  664.   result := '';
  665.  
  666.   if copy(s,1,1)='"' then
  667.     begin
  668.       result := copy(s,2,255);
  669.       if pos('"',result)=0 then
  670.         result := getfirstw(result)
  671.       else
  672.         result := copy(result,1,pos('"',result)-1);
  673.     end
  674.   else
  675.     result := getfirstw(s);
  676.  
  677.   getquoted := result;
  678. end;
  679.  
  680. function randomletter;
  681.  
  682. begin
  683.   if random(2)=0 then
  684.     randomletter := chr(ord('a')+random(26))
  685.   else
  686.     randomletter := chr(ord('A')+random(26));
  687. end;
  688.  
  689. function randomdigit;
  690.  
  691. begin
  692.   randomdigit := chr(ord('0')+random(10));
  693. end;
  694.  
  695. function getfromaddr;
  696.  
  697. var
  698.   result: string;
  699.   at: integer;
  700.  
  701. begin
  702.   at := pos('<',from);
  703.  
  704.   if at>0 then {Full Name <address>}
  705.     result := copy(from,at+1,length(from)-at-1)
  706.   else
  707.     begin
  708.       at := pos(' ',from);
  709.       if at>0 then {address (Full Name)}
  710.         result := copy(from,1,at-1)
  711.       else {address}
  712.         result := from;
  713.     end;
  714.  
  715.   getfromaddr := result;
  716. end;
  717.  
  718. {be careful with address like
  719.  
  720.   "Some (Happy) User" <some@happy.com>
  721.  
  722. - need to grab the right parts right}
  723.  
  724. function getfromname;
  725.  
  726. var
  727.   result: string;
  728.   at: integer;
  729.  
  730. begin
  731.   result := '';
  732.  
  733.   if copy(from,length(from),1)='>' then
  734.     begin
  735.       at := pos('<',from);
  736.       if at>1 then
  737.         result := copy(from,1,at-2);
  738.     end;
  739.  
  740.   if result='' then
  741.     begin
  742.       at := pos('(',from);
  743.       if at>0 then
  744.         result := copy(from,at+1,length(from)-at-1)
  745.       else
  746.         begin
  747.           at := pos('<',from);
  748.           if at>1 then
  749.             result := copy(from,1,at-2);
  750.         end;
  751.     end;
  752.  
  753.   getfromname := unquote(result);
  754. end;
  755.  
  756. function chop;
  757.  
  758. var
  759.   result: string;
  760.  
  761. begin
  762.   chop := copy(s,i+1,255);
  763. end;
  764.  
  765. function nore;
  766.  
  767. begin
  768.  
  769. {should always be 4 and 'Re: ', but uppercase and ltrim to deal with others}
  770.  
  771.   if upper(copy(s,1,3))='RE:' then
  772.     nore := ltrim(chop(s,3))
  773.   else
  774.     nore := s;
  775. end;
  776.  
  777. function monthstringtointeger;
  778.  
  779. var
  780.   result: integer;
  781.   lowermonthstr: string;
  782.  
  783. begin
  784.   result := 12;
  785.  
  786.   lowermonthstr := lower(monthstr);
  787.  
  788.   if lowermonthstr='jan' then result := 1
  789.   else if lowermonthstr='feb' then result := 2
  790.   else if lowermonthstr='mar' then result := 3
  791.   else if lowermonthstr='apr' then result := 4
  792.   else if lowermonthstr='may' then result := 5
  793.   else if lowermonthstr='jun' then result := 6
  794.   else if lowermonthstr='jul' then result := 7
  795.   else if lowermonthstr='aug' then result := 8
  796.   else if lowermonthstr='sep' then result := 9
  797.   else if lowermonthstr='oct' then result := 10
  798.   else if lowermonthstr='nov' then result := 11;
  799.  
  800.   monthstringtointeger := result;
  801. end;
  802.  
  803. function isalpha;
  804.  
  805. begin
  806.   isalpha := ( (upcase(c)>='A') and (upcase(c)<='Z') );
  807. end;
  808.  
  809. function isdigit;
  810.  
  811. begin
  812.   isdigit := (c>='0') and (c<='9');
  813. end;
  814.  
  815. function islower;
  816.  
  817. begin
  818.   islower := (c>='a') and (c<='z');
  819. end;
  820.  
  821. function snatchint;
  822.  
  823. var
  824.   intsofar: integer;
  825.  
  826. begin
  827.   intsofar := 0;
  828.  
  829.   while (length(s)>0) and not isdigit(s[1]) do
  830.     s := chop(s,1);
  831.  
  832.   while (length(s)>0) and isdigit(s[1]) do
  833.     begin
  834.       intsofar := 10*intsofar+ord(s[1])-ord('0');
  835.       s := chop(s,1);
  836.     end;
  837.  
  838.   snatchint := intsofar;
  839. end;
  840.  
  841. function isdev;
  842.  
  843. {isdev is not perfect -- it always stops on the 128th iteration, just in case}
  844.  
  845. var
  846.   result: boolean;
  847.   offs: word;
  848.   segm: word;
  849.   oldsegm: word;
  850.   foundnul: boolean;
  851.   basename: string;
  852.   i: integer;
  853.   iterations: integer;
  854.  
  855. begin
  856.   result := false;
  857.  
  858.   iterations := 0;
  859.  
  860.   segm := 0;
  861.   offs := $400;
  862.  
  863.   basename := upper(unslash(s));
  864.  
  865. {handle LPT1: case}
  866.   if copy(basename,length(basename),1)=':' then
  867.     basename := copy(basename,1,length(basename)-1);
  868.  
  869. {strip disk and path designators}
  870.   while pos(':',basename)<>0 do
  871.     basename := copy(basename,pos(':',basename)+1,255);
  872.   while pos('\',basename)<>0 do
  873.     basename := copy(basename,pos('\',basename)+1,255);
  874.  
  875. {strip anything after the first period}
  876.   if pos('.',basename)<>0 then
  877.     basename := copy(basename,1,pos('.',basename)-1);
  878.  
  879. {NUL is supposed to be guaranteed the first in the chain}
  880.   foundnul := false;
  881.   while (not foundnul) and (offs>0) do
  882.     begin
  883.  
  884. {offs is always in range 1..400 here}
  885.  
  886.       if (mem[segm:offs]=ord('N')) and
  887.        (mem[segm:offs+1]=ord('U')) and
  888.        (mem[segm:offs+2]=ord('L')) and
  889.        (mem[segm:offs+3]=ord(' ')) and
  890.        (mem[segm:offs+4]=ord(' ')) and
  891.        (mem[segm:offs+5]=ord(' ')) and
  892.        (mem[segm:offs+6]=ord(' ')) and
  893.        (mem[segm:offs+7]=ord(' ')) then
  894.         begin
  895.  
  896.           if offs<6 then
  897.             begin
  898.               writeln('!! error in isdev: offs<6, first loop -- see source');
  899.               halt(1);
  900.             end;
  901.  
  902. {$ifdef devverbose}
  903.           writeln('found NUL at ',offs);
  904.           writeln('attrib=',memw[segm:offs-6]);
  905. {$endif}
  906.  
  907.           if memw[segm:offs-6]=$8004 then
  908.             begin
  909.  
  910. {$ifdef devverbose}
  911.               writeln('looks like the real NUL to me!');
  912. {$endif}
  913.  
  914.               foundnul := true;
  915.             end;
  916.         end;
  917.  
  918.       if not foundnul then
  919.         inc(offs);
  920.     end;
  921.  
  922.   if foundnul then
  923.     begin
  924.  
  925.       while length(basename)<8 do
  926.         basename := basename+' ';
  927.  
  928.       if offs<10 then
  929.         begin
  930.           inc(offs,32);
  931.           dec(segm,2);
  932.         end;
  933.  
  934.       if offs>65000 then
  935.         begin
  936.           dec(offs,32);
  937.           inc(segm,2);
  938.         end;
  939.  
  940.       while not result and
  941.        (meml[segm:offs-10]<>$ffffffff) and
  942.        (iterations<128) do
  943.  
  944.         begin
  945.           inc(iterations);
  946.  
  947.           result := true;
  948.           for i := 0 to 7 do
  949.             result := result and (chr(mem[segm:offs+i])=basename[1+i]);
  950.  
  951. {$ifdef devverbose}
  952.           writeln('name of device=',
  953.            chr(mem[segm:offs]),
  954.            chr(mem[segm:offs+1]),
  955.            chr(mem[segm:offs+2]),
  956.            chr(mem[segm:offs+3]),
  957.            chr(mem[segm:offs+4]),
  958.            chr(mem[segm:offs+5]),
  959.            chr(mem[segm:offs+6]),
  960.            chr(mem[segm:offs+7]),
  961.            '.');
  962.  
  963.           writeln('new position: ',memw[segm:offs-10],':',memw[segm:offs-8]);
  964. {$endif}
  965.  
  966.           oldsegm := segm;
  967.           segm := memw[oldsegm:offs-8];
  968.           offs := memw[oldsegm:offs-10];
  969.  
  970.           if offs<10 then
  971.             begin
  972.               inc(offs,32);
  973.               dec(segm,2);
  974.             end;
  975.  
  976.           if offs>65000 then
  977.             begin
  978.               dec(offs,32);
  979.               inc(segm,2);
  980.             end;
  981.  
  982.           offs := offs+10;
  983.  
  984.         end;
  985.  
  986.     end;
  987.  
  988.   if iterations>=128 then
  989.     writeln('!! isdev exited due to iterations, not due to finding anything');
  990.  
  991.   isdev := result;
  992. end;
  993.  
  994. {$ifdef testfn}
  995. program testfn;
  996.  
  997. var
  998.   i: integer;
  999.   fn: string;
  1000.   f: text;
  1001.  
  1002. begin
  1003.   for i := 1 to 255 do
  1004.     begin
  1005.       fn := '';
  1006.       fn := fn+chr(((i        ) div 100)+ord('0'));
  1007.       fn := fn+chr(((i mod 100) div  10)+ord('0'));
  1008.       fn := fn+chr(((i mod  10)        )+ord('0'));
  1009.       fn := fn+'_';
  1010.       fn := fn+chr(i);
  1011.       assign(f,fn);
  1012. {$I-}
  1013.       rewrite(f);
  1014. {$I+}
  1015.       if ioresult=0 then
  1016.         close(f);
  1017.  
  1018.       writeln(i);
  1019.     end;
  1020. end.
  1021. {$endif}
  1022.  
  1023. function illegalfn;
  1024.  
  1025. const
  1026.   legalchars: set of char=
  1027.   [
  1028.    {uppercase letters}
  1029.    'A','B','C','D','E','F','G','H','I','J','K','L','M',
  1030.    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z',
  1031.  
  1032.    {lowercase letters}
  1033.    'a','b','c','d','e','f','g','h','i','j','k','l','m',
  1034.    'n','o','p','q','r','s','t','u','v','w','x','y','z',
  1035.  
  1036.    {digits}
  1037.    '0','1','2','3','4','5','6','7','8','9',
  1038.  
  1039.    {some punctuation}
  1040.    '!','#','$','%','&','(',')','-','@','^','_','`','{','}','~',
  1041.  
  1042.    {must be careful with these}
  1043.    ':','.','\',
  1044.  
  1045.    {and finally, the quote}
  1046.    ''''
  1047.   ];
  1048.  
  1049. var
  1050.   result: boolean;
  1051.   i: integer;
  1052.  
  1053. begin
  1054.   result := false;
  1055.  
  1056.   if numoccur(':',fn)>1 then
  1057.     result := true
  1058.   else if numoccur('.',fn)>1 then
  1059.     result := true
  1060.   else if fn[1]='.' then
  1061.     result := true
  1062.   else
  1063.     for i := 1 to length(fn) do
  1064.       if not (fn[i] in legalchars) then
  1065.         result := true;
  1066.  
  1067.   illegalfn := result;
  1068. end;
  1069.  
  1070. function suspiciousfn;
  1071.  
  1072. {note that unslash must have already been used!}
  1073.  
  1074. var
  1075.   result: boolean;
  1076.   upfn: string;
  1077.  
  1078. begin
  1079.   result := false;
  1080.   upfn := upper(fn);
  1081.  
  1082.   if illegalfn(upfn) then
  1083.     result := true
  1084.   else if numoccur(':',upfn)>0 then
  1085.     result := true
  1086.   else if numoccur('\',upfn)>0 then
  1087.     result := true
  1088.   else {common devices just in case isdev misses them}
  1089.     if (upfn='CON') or
  1090.      (upfn='PRN') or
  1091.      (upfn='AUX') or
  1092.      (upfn='NUL') or
  1093.      (upfn='LPT1') or
  1094.      (upfn='LPT2') or
  1095.      (upfn='LPT3') or
  1096.      (upfn='COM1') or
  1097.      (upfn='COM2') or
  1098.      (upfn='COM3') or
  1099.      (upfn='COM4') or
  1100.      (upfn='CLOCK$') then
  1101.       result := true
  1102.   else {isdev uses icky memory peeking, so don't run it if you can avoid it}
  1103.     if isdev(upfn) then
  1104.       result := true;
  1105.  
  1106.   suspiciousfn := result;
  1107. end;
  1108.  
  1109. function highestartin;
  1110.  
  1111. var
  1112.   result: word;
  1113.   fileinfo: searchrec;
  1114.  
  1115. begin
  1116.   result := 0;
  1117.  
  1118.   findfirst(groupdir+'\'+'*',archive,fileinfo);
  1119.   while doserror=0 do
  1120.     begin
  1121.       result := max(result,atoi(fileinfo.name));
  1122.       findnext(fileinfo);
  1123.     end;
  1124.  
  1125.   highestartin := result;
  1126. end;
  1127.  
  1128. function getuniqfile;
  1129.  
  1130. var
  1131.   result: string;
  1132.   mangledgroupdir: string;
  1133.  
  1134. begin
  1135.   mangledgroupdir := groupdir;
  1136.  
  1137. {}{need to keep each directory under 8 chars}
  1138.  
  1139. {avoid problems when keeping outbox copy for mail to foo@prn.com etc.}
  1140.  
  1141.   if isdev(mangledgroupdir) then
  1142.     begin
  1143.       mangledgroupdir := groupdir+'_';
  1144.  
  1145. {some device names are 8 chars, and just adding a `_' won't help}
  1146.  
  1147.       if isdev(mangledgroupdir) then
  1148.         mangledgroupdir := copy(groupdir,1,length(groupdir)-1)+'_';
  1149.     end;
  1150.  
  1151.   getuniqfile := mangledgroupdir+'\'+wtoa(highestartin(mangledgroupdir)+1);
  1152. end;
  1153.  
  1154. function getuniqfext;
  1155.  
  1156. var
  1157.   result: word;
  1158.   fileinfo: searchrec;
  1159.   filefound: string;
  1160.   mangledbasename: string;
  1161.  
  1162. begin
  1163.   result := 0;
  1164.   mangledbasename := basename;
  1165.  
  1166. {}{need to keep each directory under 8 chars}
  1167.  
  1168. {avoid problems when keeping outbox copy for mail to foo@prn.com etc.}
  1169.  
  1170.   if isdev(mangledbasename) then
  1171.     begin
  1172.       mangledbasename := basename+'_';
  1173.  
  1174. {some device names are 8 chars, and just adding a `_' won't help}
  1175.  
  1176.       if isdev(mangledbasename) then
  1177.         mangledbasename := copy(basename,1,length(basename)-1)+'_';
  1178.     end;
  1179.  
  1180.   findfirst(mangledbasename+'.*',archive,fileinfo);
  1181.   while doserror=0 do
  1182.     begin
  1183.       filefound := fileinfo.name;
  1184.       while pos('.',filefound)>0 do
  1185.         filefound := copy(filefound,pos('.',filefound)+1,255);
  1186.       result := max(result,atoi(filefound));
  1187.       findnext(fileinfo);
  1188.     end;
  1189.   getuniqfext := mangledbasename+'.'+wtoa(result+1);
  1190. end;
  1191.  
  1192. function expand;
  1193.  
  1194. var
  1195.   work: string;
  1196.   i,j: integer;
  1197.  
  1198. begin
  1199.   if pos(tab,str)=0 then
  1200.     expand := str
  1201.   else
  1202.     begin
  1203.       work := '';
  1204.       for i := 1 to length(str) do
  1205.         if length(work)<240 then
  1206.           if str[i]=tab then
  1207.             for j := 1 to 8-(length(work) and 7) do
  1208.               work := work+' '
  1209.           else
  1210.             work := work+str[i];
  1211.       expand := work;
  1212.     end;
  1213. end;
  1214.  
  1215. function rot13;
  1216.  
  1217. var
  1218.   result: string;
  1219.   upc: char;
  1220.   i: integer;
  1221.  
  1222. begin
  1223.   result := s;
  1224.  
  1225.   for i := 1 to length(result) do
  1226.     begin
  1227.       upc := upcase(result[i]);
  1228.       if (upc>='A') and (upc<='M') then
  1229.         result[i] := chr(ord(result[i])+13)
  1230.       else if (upc>='N') and (upc<='Z') then
  1231.         result[i] := chr(ord(result[i])-13);
  1232.     end;
  1233.  
  1234.   rot13 := result;
  1235. end;
  1236.  
  1237. function indir;
  1238.  
  1239. var
  1240.   fileinfo: searchrec;
  1241.  
  1242. begin
  1243.   findfirst(dir+'\'+filespec,archive,fileinfo);
  1244.   indir := (doserror=0);
  1245. end;
  1246.  
  1247. function default;
  1248.  
  1249. begin
  1250.   if possiblyemptystr='' then
  1251.     default := defaultstr
  1252.   else
  1253.     default := possiblyemptystr;
  1254. end;
  1255.  
  1256. function rpos;
  1257.  
  1258. var
  1259.   result: integer;
  1260.   i: integer;
  1261.  
  1262. begin
  1263.   result := 0;
  1264.  
  1265.   for i := 1 to length(whole)-length(sub)+1 do
  1266.     if copy(whole,i,length(sub))=sub then
  1267.       result := i;
  1268.  
  1269.   rpos := result;
  1270. end;
  1271.  
  1272. function rposc;
  1273.  
  1274. var
  1275.   result: integer;
  1276.   i: integer;
  1277.  
  1278. begin
  1279.   result := 0;
  1280.  
  1281.   for i := 1 to length(s) do
  1282.     if s[i]=c then
  1283.       result := i;
  1284.  
  1285.   rposc := result;
  1286. end;
  1287.  
  1288. function fexists;
  1289.  
  1290. var
  1291.   result: boolean;
  1292.   f: text;
  1293.  
  1294. begin
  1295.   result := false;
  1296.  
  1297.   assign(f,fn);
  1298. {$I-}
  1299.   reset(f);
  1300. {$I+}
  1301.   if ioresult=0 then
  1302.     begin
  1303.       close(f);
  1304.       result := true;
  1305.     end;
  1306.  
  1307.   fexists := result;
  1308. end;
  1309.  
  1310. function dexists;
  1311.  
  1312. var
  1313.   result: boolean;
  1314.   fileinfo: searchrec;
  1315.  
  1316. begin
  1317.   result := false;
  1318.  
  1319.   findfirst(dn,directory,fileinfo);
  1320.  
  1321.   if doserror=0 then
  1322.     if (fileinfo.attr and directory)<>0 then
  1323.       result := true;
  1324.  
  1325.   dexists := result;
  1326. end;
  1327.  
  1328. function ftimestamp;
  1329.  
  1330. var
  1331.   result: longint;
  1332.   f: text;
  1333.  
  1334. begin
  1335.   result := 0;
  1336.  
  1337.   assign(f,fn);
  1338. {$I-}
  1339.   reset(f);
  1340. {$I+}
  1341.   if ioresult=0 then
  1342.     begin
  1343.       getftime(f,result);
  1344.       close(f);
  1345.     end;
  1346.  
  1347.   ftimestamp := result;
  1348. end;
  1349.  
  1350. function withbackslash;  {nonempty gets terminated with backslash}
  1351.  
  1352. var
  1353.   result: string;
  1354.  
  1355. begin
  1356.   result := s;
  1357.   if result<>'' then
  1358.     if result[length(result)]<>'\' then
  1359.       result := result+'\';
  1360.  
  1361.   withbackslash := result;
  1362. end;
  1363.  
  1364. function nobeep;
  1365.  
  1366. var
  1367.   result: string;
  1368.  
  1369. begin
  1370.   result := crepl(s,chr(7),'^');
  1371.   nobeep := result;
  1372. end;
  1373.  
  1374. function nonastychar;
  1375.  
  1376. var
  1377.   result: string;
  1378.  
  1379. begin
  1380.   result := crepl(s,chr(7),'^');
  1381.   result := crepl(result,chr(27),'^');
  1382.   nonastychar := result;
  1383. end;
  1384.  
  1385. function gettag;
  1386.  
  1387. var
  1388.   result: string;
  1389.  
  1390. begin
  1391.   result := '';
  1392.  
  1393.   if pos(tag,s)<>0 then
  1394.     begin
  1395.       result := copy(s,pos(tag,s)+length(tag),255);
  1396.       result := getquoted(result);
  1397.     end;
  1398.  
  1399.   gettag := result;
  1400. end;
  1401.  
  1402. function hexchar;
  1403.  
  1404. begin
  1405.   if i<10 then
  1406.     hexchar := chr(ord('0')+i)
  1407.   else
  1408.     hexchar := chr(ord('a')+i-10);
  1409. end;
  1410.  
  1411. function partialmatch;
  1412.  
  1413. var
  1414.   result: boolean;
  1415.  
  1416. begin
  1417.   result := false;
  1418.  
  1419.   if (length(cmd)<=length(template)) and (length(cmd)>=length(minimum)) then
  1420.     if copy(template,1,length(cmd))=cmd then
  1421.       result := true;
  1422.  
  1423.   partialmatch := result;
  1424. end;
  1425.  
  1426. function doserrorno;  {prevents units having to include dos for 1 call}
  1427.  
  1428. begin
  1429.   doserrorno := doserror;
  1430. end;
  1431.  
  1432. function wordwith;
  1433.  
  1434. var
  1435.   result: string;
  1436.   temps: string;
  1437.  
  1438. begin
  1439.   result := '';
  1440.   temps := s;
  1441.  
  1442.   while (result='') and (temps<>'') do
  1443.     begin
  1444.       result := chopfirstw(temps);
  1445.       if pos(c,result)=0 then
  1446.         result := '';
  1447.     end;
  1448.  
  1449.   wordwith := result;
  1450. end;
  1451.  
  1452. function isasciifile;
  1453.  
  1454. const
  1455.   checkedsize=1024;
  1456.  
  1457. var
  1458.   result: boolean;
  1459.  
  1460. {$ifdef veryslowisasciifile}
  1461.   inf: file of byte;
  1462. {$endif}
  1463.   inf: file;
  1464.   whichbyte: integer;
  1465.   onebyte: byte;
  1466. {$ifdef veryslowisasciifile}
  1467.   stillsearching: boolean;
  1468. {$endif}
  1469.   buffer: array[1..checkedsize] of byte;
  1470.   numread: word;
  1471.  
  1472. begin
  1473.   result := true;
  1474.  
  1475. {$ifdef veryslowisasciifile}
  1476.   assign(inf,fn);
  1477. {$I-}
  1478.   reset(inf);
  1479. {$I+}
  1480. {$endif}
  1481.  
  1482.   assign(inf,fn);
  1483. {$I-}
  1484.   reset(inf,1);
  1485. {$I+}
  1486.  
  1487.   if ioresult<>0 then
  1488.     result := false
  1489.   else
  1490.     begin
  1491. {$ifdef veryslowisasciifile}
  1492.       stillsearching := true;
  1493.  
  1494.       for whichbyte := 1 to checkedsize do
  1495.         if stillsearching then
  1496.           begin
  1497.             if eof(inf) then
  1498.               stillsearching := false
  1499.             else
  1500.               begin
  1501.                 read(inf,onebyte);
  1502.                 if not
  1503.                 (
  1504.                  (onebyte=9)
  1505.                 or
  1506.                  (onebyte=10)
  1507.                 or
  1508.                  (onebyte=13)
  1509.                 or
  1510.                  ( (onebyte>=32) and (onebyte<=126) )
  1511.                 )
  1512.                   then
  1513.                     begin
  1514.                       result := false;
  1515.                       stillsearching := false;
  1516.                     end;
  1517.               end;
  1518.           end;
  1519.       close(inf);
  1520. {$endif}
  1521.  
  1522.       blockread(inf,buffer,checkedsize,numread);
  1523.       close(inf);
  1524.  
  1525.       for whichbyte := 1 to numread do
  1526.         if result then
  1527.           begin
  1528.             onebyte := buffer[whichbyte];
  1529.             if not
  1530.             (
  1531.              (onebyte=9)
  1532.             or
  1533.              (onebyte=10)
  1534.             or
  1535.              (onebyte=13)
  1536.             or
  1537.              ( (onebyte>=32) and (onebyte<=126) )
  1538.             )
  1539.               then
  1540.                 result := false;
  1541.           end;
  1542.  
  1543.     end;
  1544.  
  1545.   isasciifile := result;
  1546. end;
  1547.  
  1548. {$ifdef VER40}
  1549. function dosversion;
  1550.  
  1551. var
  1552.   regs: registers;
  1553.  
  1554. begin
  1555.   regs.ah := $30;
  1556.   msdos(regs);
  1557.   dosversion := regs.ax;
  1558. end;
  1559. {$endif}
  1560.  
  1561. {$ifdef floatingpoint}
  1562. function ator;
  1563.  
  1564. var
  1565.   r: real;
  1566.   code: word;
  1567.  
  1568. begin
  1569.   val(s,r,code);
  1570.   ator := r;
  1571. end;
  1572.  
  1573. function rtoa;
  1574.  
  1575. var
  1576.   a: string;
  1577.  
  1578. begin
  1579.   str(r,a);
  1580.   rtoa := a;
  1581. end;
  1582.  
  1583. function rwptoa;
  1584.  
  1585. var
  1586.   a: string;
  1587.  
  1588. begin
  1589.   str(r:width:precision,a);
  1590.   rwptoa := a;
  1591. end;
  1592. {$endif}
  1593.  
  1594. end.
  1595.